package com.atom.module.document;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Point;
import android.text.TextUtils;

import com.atom.module.document.helper.BitmapHelper;
import com.atom.module.document.helper.DocumentHelper;
import com.atom.module.document.helper.PointHelper;
import com.atom.module.image.filter.EmptyFilter;
import com.atom.module.image.filter.IImageFilter;
import com.atom.module.image.filter.SharpFilter;
import com.atom.module.logger.Logger;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;


/**
 * All rights Reserved, Designed By www.rongdasoft.com
 *
 * @version V1.0
 * @Title: Document
 * @Description:
 * @author: wuyongzheng
 * @date: 2022/3/28
 * @Copyright: 2022/3/28 www.rongdasoft.com Inc. All rights reserved.
 */
public class Document {


    public static class Entry {

        public static Entry defaultEntry(String path) {
            return new Entry(path, FilterWrapper.filter_empty_wrapper);
        }

        public static final Entry EMPTY = new Entry(null, null);

        private final String sourcePath;
        private Bitmap originalBitmap;

        private Point[] points;
        private FilterWrapper filterWrapper;
        private int rotate = 0;

        private boolean isChange = false;

        public Entry(String sourcePath, FilterWrapper filterWrapper) {
            this.sourcePath = sourcePath;
            this.filterWrapper = filterWrapper;
            if (!TextUtils.isEmpty(sourcePath)) {
                this.originalBitmap = getOriginalBitmap();
                this.points = PointHelper.createFullPoint(originalBitmap);
            }
        }

        public Entry(Entry entry) {
            this.sourcePath = entry.sourcePath;
            this.filterWrapper = entry.filterWrapper;
            this.points = entry.points;
            // 用户显示当前的旋转角度
            this.rotate = entry.rotate;
        }

        public Entry(String sourcePath, FilterWrapper filterWrapper, Point[] points, int rotate) {
            this.sourcePath = sourcePath;
            this.filterWrapper = filterWrapper;
            this.points = points;
            // 用户显示当前的旋转角度
            this.rotate = rotate;
        }

        public Bitmap getOriginalBitmap() {
            if (originalBitmap == null) {
                originalBitmap = BitmapFactory.decodeFile(sourcePath);
            }
            if (originalBitmap != null) {
                if (originalBitmap.isRecycled()) {
                    Logger.e("getOriginalBitmap is isRecycled \n %s", Logger.methods("getOriginalBitmap", 5));
                    originalBitmap = null;
                    return getOriginalBitmap();
                }
            }
            return originalBitmap;
        }

        public FilterWrapper getFilterWrapper() {
            return filterWrapper;
        }

        public void setFilterWrapper(FilterWrapper filterWrapper) {
            this.isChange = this.filterWrapper.equals(filterWrapper);
            this.filterWrapper = filterWrapper;
        }

        public Point[] getPoints() {
            return points;
        }

        public void setPoints(Point[] points) {
            if (points == null || points.length != 4) return;
            this.isChange =
                !(this.points[0].equals(points[0])
                    && this.points[1].equals(points[1])
                    && this.points[2].equals(points[3])
                    && this.points[3].equals(points[3]));
            this.points = points;
        }

        public void recycleOriginalBitmap() {
            if (originalBitmap != null && !originalBitmap.isRecycled()) {
                originalBitmap.recycle();
            }
            originalBitmap = null;
        }

        public Bitmap getRotateBitmap() {
            int currRotate = getRotate();
            if (currRotate == 0) {
                return getOriginalBitmap().copy(Bitmap.Config.RGB_565, false);
            }
            return BitmapHelper.rotateBitmap(getOriginalBitmap(), currRotate, false);
        }

        public void setRotate(int rotate) {
            this.isChange = true ;
            this.rotate += rotate;
        }

        public int getRotate() {
            return this.rotate % 360;
        }

        public String getSourcePath() {
            return sourcePath;
        }

        public String createHandlePath() {
            return sourcePath.replace(DocumentHelper.source_file, DocumentHelper.handle_file);
        }

        public boolean isChange() {
            return isChange;
        }

        // 获取当前的角度对应的狂高
        public Param getParam() {
            Param originParam = new Param(getOriginalBitmap());
            if (getRotate() == 0) return originParam;
            Matrix matrix = new Matrix();
            matrix.setRotate(getRotate());
            float[] src = originParam.toFloatArray();
            float[] dst = new float[2];
            matrix.mapPoints(dst, src);
            return new Param(dst);
        }

        public EntryWrapper toWrapper() {
            return new EntryWrapper(this.sourcePath, this.points, this.rotate, this.filterWrapper.index);
        }

        @Override
        public String toString() {
            return "Entry{" +
                "sourcePath='" + sourcePath + '\'' +
                ", points=" + Arrays.toString(points) +
                ", rotate=" + rotate +
                ", filterWrapper=" + filterWrapper +
                ", isChange=" + isChange() +
                '}';
        }
    }

    public static class EntryWrapper implements Serializable {

        private final String sourcePath;
        private final PointWrapper[] pointWrappers;
        private final int rotate;
        private final int filter;

        public EntryWrapper(String sourcePath, Point[] pointWrappers, int rotate, int filter) {
            this.sourcePath = sourcePath;
            this.pointWrappers = new PointWrapper[pointWrappers.length];
            for (int i = 0; i < pointWrappers.length; i++) {
                this.pointWrappers[i] = new PointWrapper(pointWrappers[i]);
            }
            this.rotate = rotate;
            this.filter = filter;
        }

        public Entry toEntry() {
            FilterWrapper wrapper = FilterWrapper.filter_empty_wrapper;
            for (FilterWrapper filterWrapper : filterWrappers) {
                if (filterWrapper.index == filter) {
                    wrapper = filterWrapper;
                    break;
                }
            }
            Point[] points = new Point[this.pointWrappers.length];
            for (int i = 0; i < pointWrappers.length; i++) {
                points[i] = this.pointWrappers[i].toPoint();
            }
            return new Entry(this.sourcePath, wrapper, points, this.rotate);
        }

        @Override
        public String toString() {
            return "EntryWrapper{" +
                "sourcePath='" + sourcePath + '\'' +
                ", pointWrappers=" + Arrays.toString(pointWrappers) +
                ", rotate=" + rotate +
                ", filter=" + filter +
                '}';
        }
    }

    public static class Param {
        private final int width;
        private final int height;

        public Param(int width, int height) {
            this.width = width;
            this.height = height;
        }

        public Param(Bitmap bitmap) {
            this(bitmap.getWidth(), bitmap.getHeight());
        }

        public Param(float[] floats) {
            this((int) Math.abs(floats[0]), (int) Math.abs(floats[1]));
        }

        public float[] toFloatArray() {
            return new float[]{
                this.width,
                this.height
            };
        }

        public int getHeight() {
            return height;
        }

        public int getWidth() {
            return width;
        }

        @Override
        public String toString() {
            return "Param{" +
                "width=" + width +
                ", height=" + height +
                '}';
        }
    }

    public static class PointWrapper implements Serializable {
        final int x;
        final int y;

        public PointWrapper(Point point) {
            this.x = point.x;
            this.y = point.y;
        }

        public Point toPoint() {
            return new Point(this.x, this.y);
        }

        @Override
        public String toString() {
            return "PointWrapper{" +
                "x=" + x +
                ", y=" + y +
                '}';
        }
    }

    public enum FilterWrapper {
        filter_empty_wrapper(0, "原图", new EmptyFilter()),
        filter_sharp_wrapper(1, "增强并锐化", new SharpFilter());

        public final int index;
        public final String name;
        public final IImageFilter filter;

        FilterWrapper(int index, String name, IImageFilter filter) {
            this.index = index;
            this.name = name;
            this.filter = filter;
        }
    }

    public static List<FilterWrapper> filterWrappers = new ArrayList<>();
    private static FilterWrapper current_filter_wrapper = null;

    static {
        filterWrappers.add(FilterWrapper.filter_empty_wrapper);
        filterWrappers.add(FilterWrapper.filter_sharp_wrapper);
        current_filter_wrapper = FilterWrapper.filter_empty_wrapper;
    }

    public static FilterWrapper getCurrentFilter() {
        if (current_filter_wrapper == null) {
            current_filter_wrapper = FilterWrapper.filter_empty_wrapper;
        }
        return current_filter_wrapper;
    }

    public static void setCurrentFilter(FilterWrapper filterWrapper) {
        current_filter_wrapper = filterWrapper;
    }

    //------------------------------------------------------

    private static final ArrayList<Document.Entry> documentEntryList = new ArrayList<>();

    public static Document.Entry addDocument(String path, FilterWrapper filterWrapper) {
        if (filterWrapper == null) {
            filterWrapper = FilterWrapper.filter_empty_wrapper;
        }
        Entry entry = new Entry(path, filterWrapper);
        documentEntryList.add(entry);
        return entry;
    }

    public static void addAllDocument(Collection<Document.Entry> collection) {
        documentEntryList.addAll(collection);
    }

    public static void addDocument(int index, Document.Entry entry) {
        if (index < 0 || index > documentEntryList.size()) {
            return;
        }
        if (documentEntryList.isEmpty()) {
            documentEntryList.add(entry);
            return;
        }
        if (documentEntryList.contains(entry)) {
            return;
        }
        documentEntryList.add(index, entry);
    }

    public static int removeDocument(Document.Entry entry) {
        if (documentEntryList.isEmpty()) return -1;
        if (!documentEntryList.contains(entry)) return -1;
        int index = documentEntryList.indexOf(entry);
        documentEntryList.remove(index);
        return index;
    }

    public static Document.Entry removeDocument(int index) {
        if (index < 0 || index > documentEntryList.size()) return null;
        return documentEntryList.remove(index);
    }

    public static void clearDocument() {
        documentEntryList.clear();
    }

    public static boolean isEmptyDocument() {
        return documentEntryList.isEmpty();
    }

    public static Entry lastDocument() {
        return documentEntryList.get(documentEntryList.size() - 1);
    }

    public static int sizeDocument() {
        return documentEntryList.size();
    }

    public static List<Document.Entry> getDocument() {
        return documentEntryList;
    }

    public static Document.Entry getDocumentByIndex(int index) {
        if (index < 0 || index > documentEntryList.size() - 1) {
            return null;
        }
        return documentEntryList.get(index);
    }


}
